Advanced Data Journalism Final Project
Data from:
https://data.mo.gov/Health/Missouri-Cooling-Centers-Sites/ks2s-yguy
https://ephtracking.cdc.gov/DataExplorer/?c=35&i=88&m=-1
https://public.tableau.com/app/profile/samantha2462/viz/shared/437ZHKXJZ
https://moboscoc.org/resources/data/point-in-time-count-reports/
Step 1: Load libraries
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.2 ──✔ ggplot2 3.4.0 ✔ purrr 1.0.1
✔ tibble 3.1.8 ✔ dplyr 1.0.10
✔ tidyr 1.3.0 ✔ stringr 1.5.0
✔ readr 2.1.3 ✔ forcats 0.5.2 ── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
library(lubridate)
Attaching package: ‘lubridate’
The following objects are masked from ‘package:base’:
date, intersect, setdiff, union
library(ggplot2)
library(dplyr)
library(janitor)
Attaching package: ‘janitor’
The following objects are masked from ‘package:stats’:
chisq.test, fisher.test
library(maps)
Attaching package: ‘maps’
The following object is masked from ‘package:purrr’:
map
library(leaflet)
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
library(ggiraph)
library(plotly)
Registered S3 method overwritten by 'data.table':
method from
print.data.table
Attaching package: ‘plotly’
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
#Animation Libraries
#I opted not to animate data because none of the data I collected seemed well-suited for animating over time. I did, however, include the code I used to try and animate the bar graph at the end of the assignment.
library(gganimate)
library(sp)
library(viridis)
Loading required package: viridisLite
Attaching package: ‘viridis’
The following object is masked from ‘package:maps’:
unemp
library(htmltools)
library(gapminder)
library(gifski)
library(png)
library(tmap)
Step 2: Load data
We will be using three data sets. One contains the coordinates and
details for cooling centers serving Missouri and another contains
heat-related hospitalizations over the last several years. The last one
contains information about people experiencing homelessness at a
specific point in time from the U.S. Department of Housing and Urban
Development.
coolingcenters <- read_csv("Final Project/Missouri_Cooling_Centers_Sites.csv")
Rows: 538 Columns: 11── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (10): FACILITY, ADDRESS, CITY, COUNTY, PHONE, HOURS OF OPERATION, Location, ADA-Accessible, TRANSPORTATION, state
dbl (1): ZIPCODE
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
heathospitalizations <- read_csv("Final Project/heatrate.csv")
New names:Rows: 602 Columns: 6── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): StateFIPS, State, Data Comment
dbl (2): Year, Value
lgl (1): ...6
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
hud_mo <- read_csv("Final Project/HUDmo.csv")
Rows: 101 Columns: 4── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): County, Measure Names
dbl (2): Measure Values, Total
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Step 3: Clean data
Clean & organize cooling centers data.
Our data needs to be properly — and specifically — formatted so it
can be easily visualized.
#First, I'm separating the latitude and longitude into separate boxes.
coolingcentersclean <- coolingcenters %>%
separate(Location, sep=", ", into=c("latitude", "longitude"))
#I'm also cleaning up these boxes by removing the parentheses from them.
coolingcentersclean <- coolingcentersclean %>%
mutate(lat = str_replace(latitude, "[(]", ""))
coolingcentersclean <- coolingcentersclean %>%
mutate(long = str_replace(longitude, "[)]", ""))
#I'm going to change the state abbreviations to their names so it will be easier to combine with the states data.
coolingcentersclean <- coolingcentersclean %>% mutate(region = case_when(
grepl("MO", state, ignore.case=T) ~ "missouri",
grepl("IL", state, ignore.case=T) ~ "illinois",
grepl("KS", state, ignore.case=T) ~ "kansas"))
#I'm going to remove the improperly formatting latitude and longitude from the dataset.
coolingcentersclean <- subset (coolingcentersclean, select = -latitude)
coolingcentersclean <- subset (coolingcentersclean, select = -longitude)
#We'll need our coordinates to be numbers so we can plot them.
coolingcentersclean$lat <- as.numeric(coolingcentersclean$lat)
coolingcentersclean$long <- as.numeric(coolingcentersclean$long)
#Lastly, I'll be cleaning the names with janitor.
coolingcentersclean <- clean_names(coolingcentersclean)
Clean & organize heat data
#This dataset is relatively clean, so I'm just going to clean the names and then remove the column at the end.
heathospitalizations <- clean_names(heathospitalizations)
heathosptializations <- tolower(heathospitalizations$state)
heathospitalizations <- subset (heathospitalizations, select = -x6)
Clean & organize HUD data
#This dataset is relatively clean, so I'm just going to clean the names and rename the unsheltered column for the sake of ease.
hud_mo <- clean_names(hud_mo)
hud_mo <- hud_mo %>% rename(unsheltered_total = measure_values)
Step 4: Load map data
states <- map_data("state") %>% filter(region=="missouri" | region == "illinois" | region == "kansas")
statescounties <- map_data("county")
mocounties <- map_data("county") %>% filter(region == "missouri")
Step 5: Create custom interactive dot map
By using county-level data from the maps package and plotly, we can
create our own custom interactive dot map.
dotmap_ <- ggplot(statescounties, aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "#F8F9F9", color = "darkgray", linewidth=.1) +
geom_point(data=coolingcentersclean, aes(group = NULL, text = paste("Location:", facility)), alpha=.5, size=.7, color="#EE9253") +
coord_fixed(1.3) +
theme_void() +
labs(title="Cooling Centers in Missouri in 2022", caption = "Data from data.mo.gov") + theme_void()
Warning: Ignoring unknown aesthetics: text
dotmap <- ggplotly(dotmap_, tooltip = "text")
Step 6: Create interactive dot map with leaflet
Leaflet is a simpler way to plot data interactively.
interactivedotmap <- leaflet() %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addCircleMarkers(
data = coolingcentersclean,
color = "#EE9253",
opacity = 0.5,
radius = 1,
~long, ~lat, popup = ~htmlEscape(facility))
Step 7: Create an interactive bar graph
Similar to how we created a custom interactive dot map, we can do the
same for bar graphs.
#I'm going to create a tooltip first to make the bar graph interactive.
heathospitalizations <- heathospitalizations %>% mutate(
tooltip_text = paste0(year, " - ", value, "%"))
colors <- c("National Average" = "red")
#Now, I'm going to use ggplot to create the bar graph.
bar_graph_ <- heathospitalizations %>%
filter(state=="Missouri") %>%
ggplot(aes(x=year, y=value, tooltip = tooltip_text, data_id = state)) +
theme_minimal() +
geom_col_interactive(width=.7, size = 0.2, fill="#EE9253") +
geom_hline_interactive(aes(yintercept = 2.010133, tooltip = "National Average: 2.010133%", linetype="National Average")) +
scale_linetype_manual(name = "", values = "solid") +
scale_size_manual(aes(size=.05)) +
theme(axis.text=element_text(size = 7), axis.title=element_text(size=7), title=element_text(size=7), legend.position = "bottom", legend.text = element_text(size=5), legend.title = element_text(size=7)) +
labs(title = "Percentage of heat-related illness hospitalizations in Missouri per 100k people 2000-2020", subtitle = "Data from CDC") +
ylab("Percentage of heat hospitalizations") +
xlab("Year")
#Girafe will let us make the graph interactive.
bar_graph <- girafe(ggobj = bar_graph_, width_svg = 5, height_svg = 3, gg_hline1)
Step 8: Create an interactive chloropleth graph
hud_mo <- hud_mo %>%
mutate(county = str_replace(county, '\\.', ''))
hud_states <-
hud_mo %>%
mutate(county = str_to_lower(county)) %>%
right_join(mocounties, by = c("county" = "subregion"))
hud_states <- hud_states %>% mutate(
tooltip_text = paste0(county, " - ", unsheltered_total))
chloro_map_ <-ggplot(hud_states, aes(x = long, y = lat, group = group, fill = unsheltered_total, tooltip = tooltip_text, data_id = county)) +
theme_void() +
geom_polygon_interactive(colour = "white", linewidth = .1) +
coord_fixed(1.3) +
scale_fill_continuous(low = '#F9E79F',high = '#D4AC0D', n.breaks=10, name="Total unsheltered individuals") +
labs(title = "Total people who are unsheltered in Missouri counties — 2019",subtitle = "Data from CDC") +
theme(title=element_text(size=7), legend.position = "right", legend.text = element_text(size=5), legend.title = element_text(size=7))
chloro_map <- girafe(ggobj = chloro_map_, width_svg = 5, height_svg = 3)
Step 9: Do some basic analysis
coolingcentersclean %>%
filter(transportation == "Yes")
#No centers provide transportation
coolingcentersclean %>%
filter(ada_accessible == "No")
#All centers are ADA accessible
coolingcentersclean %>%
group_by(county) %>%
count(county) %>%
arrange(desc(n))
#Jackson County has the most cooling centers followed by St. Louis county and then Madison
coolingcentersclean %>%
filter(county == "Boone")
#Boone County has 6 cooling centers
coolingcentersclean %>%
filter(grepl("sun", hours_of_operation, ignore.case=T))
#58 centers are open on Sundays
heathospitalizations %>%
arrange(desc(value))
#California had the highest heat-related hospitalization rate in 2020; Missouri had the sixth highest rate in 2011 at 7.6.
heathospitalizations %>%
filter(state=="Missouri") %>%
arrange(desc(value))
#Missouri had its highest number of heat-related hospitalizations in 2011
heathospitalizations %>%
summarise(average = mean(value))
#The average percentage of heat-related illness hospitalizations from 2000 to 2021 using availble data was 2.010133%.
heathospitalizations %>%
group_by(state) %>%
summarise(average = mean(value)) %>%
arrange(desc(average))
#Missouri has the second highest rate of the data reported.
Story Package
Important statistics and data analysis to include in the
story:
In the last two decades, Missouri ranks in the top ten out of
reporting states for the highest rate of heat-related illnesses per
100,000 people. In 2011, the rate in Missouri reached 7.6%, ranking it
number 6 behind Arizona.
Missouri currently reports 538 cooling centers. 58 of those cooling
centers are open on Sundays.
Graphs to include in the story:
dotmap
interactivedotmap
Methodology:
Three data sets were used and analyzed in this story package.
The first data set documents the locations of cooling centers in the
state of Missouri. This data is from 2022 and was collected from
data.mo.gov. It is reported by the Missouri Department of Health &
Senior Services. The data only includes cooling centers that are
reported to the Missouri Department of Health & Senior Services, and
therefore may exclude some cooling centers.
The second data set documents the percent of age-adjusted
heat-related illness hospitalizations in the United States per 100,000
people. It was accessed from the Centers for Disease Control. It is
important to note that all states report data every year. In my
analysis, I included all states’ data. In creating the bar chart,
however, I included filtered for data from only Missouri, for all years
available from 2000 to 2021.
The third data set documents the number of unsheltered individuals
experiencing homelessness in 2019, which is the most recent data
available for download. It comes from the Missouri Balance of State
Continua of Care, as required by the Missouri Department of Health &
Senior Services. Some counties are not reported in the data. In the
chart, these counties are listed with data as “N/A”.
Animation code:
This code may take a while to load, and requires rendering packages
to show the animation.
animatedgraph <- heathospitalizations %>%
filter(state=="Missouri" | state=="Arizona") %>%
ggplot(aes(x=state, y=value, fill=state)) +
theme_minimal() +
theme(axis.text=element_text(size = 7), axis.title=element_text(size=7), title=element_text(size=7), legend.position = "bottom", legend.text = element_text(size=5), legend.title = element_text(size=7)) +
labs(title = "Percentage of heat-related illness hospitalizations in Missouri and Arizona per 100k people 2000-2020", subtitle = "Data from CDC") +
ylab("Percentage of heat hospitalizations") +
xlab("Year")
animatedgraph + geom_bar(stat='identity') +
transition_states(
year,
transition_length = 20,
state_length = 1) +
ease_aes('sine-in-out') +
transition_time(year) +
labs(title = "Year: {frame_time}")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyAqKkFkdmFuY2VkIERhdGEgSm91cm5hbGlzbSBGaW5hbCBQcm9qZWN0KioKCkRhdGEgZnJvbToKCjxodHRwczovL2RhdGEubW8uZ292L0hlYWx0aC9NaXNzb3VyaS1Db29saW5nLUNlbnRlcnMtU2l0ZXMva3Mycy15Z3V5PgoKPGh0dHBzOi8vZXBodHJhY2tpbmcuY2RjLmdvdi9EYXRhRXhwbG9yZXIvP2M9MzUmaT04OCZtPS0xPgoKPGh0dHBzOi8vcHVibGljLnRhYmxlYXUuY29tL2FwcC9wcm9maWxlL3NhbWFudGhhMjQ2Mi92aXovc2hhcmVkLzQzN1pIS1hKWj4KCjxodHRwczovL21vYm9zY29jLm9yZy9yZXNvdXJjZXMvZGF0YS9wb2ludC1pbi10aW1lLWNvdW50LXJlcG9ydHMvPgoKIyMjIFN0ZXAgMTogTG9hZCBsaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KG1hcHMpCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShnZ2lyYXBoKQpsaWJyYXJ5KHBsb3RseSkKCiNBbmltYXRpb24gTGlicmFyaWVzCiNJIG9wdGVkIG5vdCB0byBhbmltYXRlIGRhdGEgYmVjYXVzZSBub25lIG9mIHRoZSBkYXRhIEkgY29sbGVjdGVkIHNlZW1lZCB3ZWxsLXN1aXRlZCBmb3IgYW5pbWF0aW5nIG92ZXIgdGltZS4gSSBkaWQsIGhvd2V2ZXIsIGluY2x1ZGUgdGhlIGNvZGUgSSB1c2VkIHRvIHRyeSBhbmQgYW5pbWF0ZSB0aGUgYmFyIGdyYXBoIGF0IHRoZSBlbmQgb2YgdGhlIGFzc2lnbm1lbnQuCgpsaWJyYXJ5KGdnYW5pbWF0ZSkKbGlicmFyeShzcCkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGh0bWx0b29scykKbGlicmFyeShnYXBtaW5kZXIpCmxpYnJhcnkoZ2lmc2tpKQpsaWJyYXJ5KHBuZykKbGlicmFyeSh0bWFwKQoKCmBgYAoKIyMjIFN0ZXAgMjogTG9hZCBkYXRhCgpXZSB3aWxsIGJlIHVzaW5nIHRocmVlIGRhdGEgc2V0cy4gT25lIGNvbnRhaW5zIHRoZSBjb29yZGluYXRlcyBhbmQgZGV0YWlscyBmb3IgY29vbGluZyBjZW50ZXJzIHNlcnZpbmcgTWlzc291cmkgYW5kIGFub3RoZXIgY29udGFpbnMgaGVhdC1yZWxhdGVkIGhvc3BpdGFsaXphdGlvbnMgb3ZlciB0aGUgbGFzdCBzZXZlcmFsIHllYXJzLiBUaGUgbGFzdCBvbmUgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgcGVvcGxlIGV4cGVyaWVuY2luZyBob21lbGVzc25lc3MgYXQgYSBzcGVjaWZpYyBwb2ludCBpbiB0aW1lIGZyb20gdGhlIFUuUy4gRGVwYXJ0bWVudCBvZiBIb3VzaW5nIGFuZCBVcmJhbiBEZXZlbG9wbWVudC4KCmBgYHtyfQpjb29saW5nY2VudGVycyA8LSByZWFkX2NzdigiRmluYWwgUHJvamVjdC9NaXNzb3VyaV9Db29saW5nX0NlbnRlcnNfU2l0ZXMuY3N2IikKCmhlYXRob3NwaXRhbGl6YXRpb25zIDwtIHJlYWRfY3N2KCJGaW5hbCBQcm9qZWN0L2hlYXRyYXRlLmNzdiIpCgpodWRfbW8gPC0gcmVhZF9jc3YoIkZpbmFsIFByb2plY3QvSFVEbW8uY3N2IikKYGBgCgojIyMgU3RlcCAzOiBDbGVhbiBkYXRhCgpDbGVhbiAmIG9yZ2FuaXplIGNvb2xpbmcgY2VudGVycyBkYXRhLgoKT3VyIGRhdGEgbmVlZHMgdG8gYmUgcHJvcGVybHkgLS0tIGFuZCBzcGVjaWZpY2FsbHkgLS0tIGZvcm1hdHRlZCBzbyBpdCBjYW4gYmUgZWFzaWx5IHZpc3VhbGl6ZWQuCgpgYGB7cn0KI0ZpcnN0LCBJJ20gc2VwYXJhdGluZyB0aGUgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSBpbnRvIHNlcGFyYXRlIGJveGVzLiAKY29vbGluZ2NlbnRlcnNjbGVhbiA8LSBjb29saW5nY2VudGVycyAlPiUgCiAgc2VwYXJhdGUoTG9jYXRpb24sIHNlcD0iLCAiLCBpbnRvPWMoImxhdGl0dWRlIiwgImxvbmdpdHVkZSIpKQoKI0knbSBhbHNvIGNsZWFuaW5nIHVwIHRoZXNlIGJveGVzIGJ5IHJlbW92aW5nIHRoZSBwYXJlbnRoZXNlcyBmcm9tIHRoZW0uCmNvb2xpbmdjZW50ZXJzY2xlYW4gPC0gY29vbGluZ2NlbnRlcnNjbGVhbiAlPiUKIG11dGF0ZShsYXQgPSBzdHJfcmVwbGFjZShsYXRpdHVkZSwgIlsoXSIsICIiKSkKCmNvb2xpbmdjZW50ZXJzY2xlYW4gPC0gY29vbGluZ2NlbnRlcnNjbGVhbiAlPiUKIG11dGF0ZShsb25nID0gc3RyX3JlcGxhY2UobG9uZ2l0dWRlLCAiWyldIiwgIiIpKQoKI0knbSBnb2luZyB0byBjaGFuZ2UgdGhlIHN0YXRlIGFiYnJldmlhdGlvbnMgdG8gdGhlaXIgbmFtZXMgc28gaXQgd2lsbCBiZSBlYXNpZXIgdG8gY29tYmluZSB3aXRoIHRoZSBzdGF0ZXMgZGF0YS4KY29vbGluZ2NlbnRlcnNjbGVhbiA8LSBjb29saW5nY2VudGVyc2NsZWFuICU+JSBtdXRhdGUocmVnaW9uID0gY2FzZV93aGVuKAogIGdyZXBsKCJNTyIsIHN0YXRlLCBpZ25vcmUuY2FzZT1UKSB+ICJtaXNzb3VyaSIsCiAgZ3JlcGwoIklMIiwgc3RhdGUsIGlnbm9yZS5jYXNlPVQpIH4gImlsbGlub2lzIiwKICBncmVwbCgiS1MiLCBzdGF0ZSwgaWdub3JlLmNhc2U9VCkgfiAia2Fuc2FzIikpCgojSSdtIGdvaW5nIHRvIHJlbW92ZSB0aGUgaW1wcm9wZXJseSBmb3JtYXR0aW5nIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgZnJvbSB0aGUgZGF0YXNldC4gCmNvb2xpbmdjZW50ZXJzY2xlYW4gPC0gc3Vic2V0IChjb29saW5nY2VudGVyc2NsZWFuLCBzZWxlY3QgPSAtbGF0aXR1ZGUpCmNvb2xpbmdjZW50ZXJzY2xlYW4gPC0gc3Vic2V0IChjb29saW5nY2VudGVyc2NsZWFuLCBzZWxlY3QgPSAtbG9uZ2l0dWRlKQoKI1dlJ2xsIG5lZWQgb3VyIGNvb3JkaW5hdGVzIHRvIGJlIG51bWJlcnMgc28gd2UgY2FuIHBsb3QgdGhlbS4KY29vbGluZ2NlbnRlcnNjbGVhbiRsYXQgPC0gYXMubnVtZXJpYyhjb29saW5nY2VudGVyc2NsZWFuJGxhdCkKY29vbGluZ2NlbnRlcnNjbGVhbiRsb25nIDwtIGFzLm51bWVyaWMoY29vbGluZ2NlbnRlcnNjbGVhbiRsb25nKQoKI0xhc3RseSwgSSdsbCBiZSBjbGVhbmluZyB0aGUgbmFtZXMgd2l0aCBqYW5pdG9yLiAKY29vbGluZ2NlbnRlcnNjbGVhbiA8LSBjbGVhbl9uYW1lcyhjb29saW5nY2VudGVyc2NsZWFuKQpgYGAKCkNsZWFuICYgb3JnYW5pemUgaGVhdCBkYXRhCgpgYGB7cn0KI1RoaXMgZGF0YXNldCBpcyByZWxhdGl2ZWx5IGNsZWFuLCBzbyBJJ20ganVzdCBnb2luZyB0byBjbGVhbiB0aGUgbmFtZXMgYW5kIHRoZW4gcmVtb3ZlIHRoZSBjb2x1bW4gYXQgdGhlIGVuZC4KaGVhdGhvc3BpdGFsaXphdGlvbnMgPC0gY2xlYW5fbmFtZXMoaGVhdGhvc3BpdGFsaXphdGlvbnMpCmhlYXRob3NwdGlhbGl6YXRpb25zIDwtIHRvbG93ZXIoaGVhdGhvc3BpdGFsaXphdGlvbnMkc3RhdGUpCgpoZWF0aG9zcGl0YWxpemF0aW9ucyA8LSBzdWJzZXQgKGhlYXRob3NwaXRhbGl6YXRpb25zLCBzZWxlY3QgPSAteDYpCmBgYAoKQ2xlYW4gJiBvcmdhbml6ZSBIVUQgZGF0YQoKYGBge3J9CiNUaGlzIGRhdGFzZXQgaXMgcmVsYXRpdmVseSBjbGVhbiwgc28gSSdtIGp1c3QgZ29pbmcgdG8gY2xlYW4gdGhlIG5hbWVzIGFuZCByZW5hbWUgdGhlIHVuc2hlbHRlcmVkIGNvbHVtbiBmb3IgdGhlIHNha2Ugb2YgZWFzZS4KaHVkX21vIDwtIGNsZWFuX25hbWVzKGh1ZF9tbykKaHVkX21vIDwtIGh1ZF9tbyAlPiUgcmVuYW1lKHVuc2hlbHRlcmVkX3RvdGFsID0gbWVhc3VyZV92YWx1ZXMpCmBgYAoKIyMjIFN0ZXAgNDogTG9hZCBtYXAgZGF0YQoKYGBge3J9CnN0YXRlcyA8LSBtYXBfZGF0YSgic3RhdGUiKSAlPiUgZmlsdGVyKHJlZ2lvbj09Im1pc3NvdXJpIiB8IHJlZ2lvbiA9PSAiaWxsaW5vaXMiIHwgcmVnaW9uID09ICJrYW5zYXMiKQoKc3RhdGVzY291bnRpZXMgPC0gbWFwX2RhdGEoImNvdW50eSIpCgptb2NvdW50aWVzIDwtIG1hcF9kYXRhKCJjb3VudHkiKSAlPiUgZmlsdGVyKHJlZ2lvbiA9PSAgIm1pc3NvdXJpIikKYGBgCgojIyMgU3RlcCA1OiBDcmVhdGUgY3VzdG9tIGludGVyYWN0aXZlIGRvdCBtYXAKCkJ5IHVzaW5nIGNvdW50eS1sZXZlbCBkYXRhIGZyb20gdGhlIG1hcHMgcGFja2FnZSBhbmQgcGxvdGx5LCB3ZSBjYW4gY3JlYXRlIG91ciBvd24gY3VzdG9tIGludGVyYWN0aXZlIGRvdCBtYXAuCgpgYGB7cn0KZG90bWFwXyA8LSBnZ3Bsb3Qoc3RhdGVzY291bnRpZXMsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCkpICsKICBnZW9tX3BvbHlnb24oZmlsbCA9ICIjRjhGOUY5IiwgY29sb3IgPSAiZGFya2dyYXkiLCBsaW5ld2lkdGg9LjEpICsKICBnZW9tX3BvaW50KGRhdGE9Y29vbGluZ2NlbnRlcnNjbGVhbiwgYWVzKGdyb3VwID0gTlVMTCwgdGV4dCA9IHBhc3RlKCJMb2NhdGlvbjoiLCBmYWNpbGl0eSkpLCAgIGFscGhhPS41LCBzaXplPS43LCBjb2xvcj0iI0VFOTI1MyIpICsgICAKICBjb29yZF9maXhlZCgxLjMpICsKICB0aGVtZV92b2lkKCkgKwogIGxhYnModGl0bGU9IkNvb2xpbmcgQ2VudGVycyBpbiBNaXNzb3VyaSBpbiAyMDIyIiwgY2FwdGlvbiA9ICJEYXRhIGZyb20gZGF0YS5tby5nb3YiKSArIHRoZW1lX3ZvaWQoKSAKCmRvdG1hcCA8LSBnZ3Bsb3RseShkb3RtYXBfLCB0b29sdGlwID0gInRleHQiKQoKYGBgCgojIyMgU3RlcCA2OiBDcmVhdGUgaW50ZXJhY3RpdmUgZG90IG1hcCB3aXRoIGxlYWZsZXQKCkxlYWZsZXQgaXMgYSBzaW1wbGVyIHdheSB0byBwbG90IGRhdGEgaW50ZXJhY3RpdmVseS4KCmBgYHtyfQppbnRlcmFjdGl2ZWRvdG1hcCA8LSBsZWFmbGV0KCkgJT4lIAogICAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgICBhZGRDaXJjbGVNYXJrZXJzKAogICAgZGF0YSA9IGNvb2xpbmdjZW50ZXJzY2xlYW4sCiAgICBjb2xvciA9ICIjRUU5MjUzIiwKICAgIG9wYWNpdHkgPSAwLjUsCiAgICByYWRpdXMgPSAxLAogICAgfmxvbmcsIH5sYXQsIHBvcHVwID0gfmh0bWxFc2NhcGUoZmFjaWxpdHkpKQpgYGAKCiMjIyBTdGVwIDc6IENyZWF0ZSBhbiBpbnRlcmFjdGl2ZSBiYXIgZ3JhcGgKClNpbWlsYXIgdG8gaG93IHdlIGNyZWF0ZWQgYSBjdXN0b20gaW50ZXJhY3RpdmUgZG90IG1hcCwgd2UgY2FuIGRvIHRoZSBzYW1lIGZvciBiYXIgZ3JhcGhzLgoKYGBge3J9CiNJJ20gZ29pbmcgdG8gY3JlYXRlIGEgdG9vbHRpcCBmaXJzdCB0byBtYWtlIHRoZSBiYXIgZ3JhcGggaW50ZXJhY3RpdmUuIApoZWF0aG9zcGl0YWxpemF0aW9ucyA8LSBoZWF0aG9zcGl0YWxpemF0aW9ucyAlPiUgbXV0YXRlKAogICAgdG9vbHRpcF90ZXh0ID0gcGFzdGUwKHllYXIsICIgLSAiLCB2YWx1ZSwgIiUiKSkKCmNvbG9ycyA8LSBjKCJOYXRpb25hbCBBdmVyYWdlIiA9ICJyZWQiKQoKCiNOb3csIEknbSBnb2luZyB0byB1c2UgZ2dwbG90IHRvIGNyZWF0ZSB0aGUgYmFyIGdyYXBoLgpiYXJfZ3JhcGhfIDwtIGhlYXRob3NwaXRhbGl6YXRpb25zICU+JSAKICBmaWx0ZXIoc3RhdGU9PSJNaXNzb3VyaSIpICU+JSAKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT12YWx1ZSwgdG9vbHRpcCA9IHRvb2x0aXBfdGV4dCwgZGF0YV9pZCA9IHN0YXRlKSkgKyAKICB0aGVtZV9taW5pbWFsKCkgKwogIGdlb21fY29sX2ludGVyYWN0aXZlKHdpZHRoPS43LCBzaXplID0gMC4yLCBmaWxsPSIjRUU5MjUzIikgKyAKICBnZW9tX2hsaW5lX2ludGVyYWN0aXZlKGFlcyh5aW50ZXJjZXB0ID0gMi4wMTAxMzMsIHRvb2x0aXAgPSAiTmF0aW9uYWwgQXZlcmFnZTogMi4wMTAxMzMlIiwgbGluZXR5cGU9Ik5hdGlvbmFsIEF2ZXJhZ2UiKSkgKwogICAgICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbChuYW1lID0gIiIsIHZhbHVlcyA9ICJzb2xpZCIpICsKICAgICAgICBzY2FsZV9zaXplX21hbnVhbChhZXMoc2l6ZT0uMDUpKSArCnRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZSA9IDcpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTcpLCB0aXRsZT1lbGVtZW50X3RleHQoc2l6ZT03KSwgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTcpKSArCmxhYnModGl0bGUgPSAiUGVyY2VudGFnZSBvZiBoZWF0LXJlbGF0ZWQgaWxsbmVzcyBob3NwaXRhbGl6YXRpb25zIGluIE1pc3NvdXJpIHBlciAxMDBrIHBlb3BsZSAyMDAwLTIwMjAiLCBzdWJ0aXRsZSA9ICJEYXRhIGZyb20gQ0RDIikgKwp5bGFiKCJQZXJjZW50YWdlIG9mIGhlYXQgaG9zcGl0YWxpemF0aW9ucyIpICsKeGxhYigiWWVhciIpCgojR2lyYWZlIHdpbGwgbGV0IHVzIG1ha2UgdGhlIGdyYXBoIGludGVyYWN0aXZlLgpiYXJfZ3JhcGggPC0gZ2lyYWZlKGdnb2JqID0gYmFyX2dyYXBoXywgd2lkdGhfc3ZnID0gNSwgaGVpZ2h0X3N2ZyA9IDMsIGdnX2hsaW5lMSkKCmBgYAoKIyMjIFN0ZXAgODogQ3JlYXRlIGFuIGludGVyYWN0aXZlIGNobG9yb3BsZXRoIGdyYXBoCgpgYGB7cn0KaHVkX21vIDwtIGh1ZF9tbyAlPiUgCiBtdXRhdGUoY291bnR5ID0gc3RyX3JlcGxhY2UoY291bnR5LCAnXFwuJywgJycpKQoKaHVkX3N0YXRlcyA8LSAKICBodWRfbW8gJT4lIAogIG11dGF0ZShjb3VudHkgPSBzdHJfdG9fbG93ZXIoY291bnR5KSkgJT4lIAogIHJpZ2h0X2pvaW4obW9jb3VudGllcywgYnkgPSBjKCJjb3VudHkiID0gInN1YnJlZ2lvbiIpKQoKaHVkX3N0YXRlcyA8LSBodWRfc3RhdGVzICU+JSBtdXRhdGUoCiAgICB0b29sdGlwX3RleHQgPSBwYXN0ZTAoY291bnR5LCAiIC0gIiwgdW5zaGVsdGVyZWRfdG90YWwpKQoKY2hsb3JvX21hcF8gPC1nZ3Bsb3QoaHVkX3N0YXRlcywgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gdW5zaGVsdGVyZWRfdG90YWwsIHRvb2x0aXAgPSB0b29sdGlwX3RleHQsIGRhdGFfaWQgPSBjb3VudHkpKSArCiAgdGhlbWVfdm9pZCgpICsKICBnZW9tX3BvbHlnb25faW50ZXJhY3RpdmUoY29sb3VyID0gIndoaXRlIiwgbGluZXdpZHRoID0gLjEpICsKICBjb29yZF9maXhlZCgxLjMpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gJyNGOUU3OUYnLGhpZ2ggPSAnI0Q0QUMwRCcsIG4uYnJlYWtzPTEwLCBuYW1lPSJUb3RhbCB1bnNoZWx0ZXJlZCBpbmRpdmlkdWFscyIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIHBlb3BsZSB3aG8gYXJlIHVuc2hlbHRlcmVkIGluIE1pc3NvdXJpIGNvdW50aWVzIOKAlCAyMDE5IixzdWJ0aXRsZSA9ICJEYXRhIGZyb20gQ0RDIikgKwogIHRoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTcpLCBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT03KSkKCmNobG9yb19tYXAgPC0gZ2lyYWZlKGdnb2JqID0gY2hsb3JvX21hcF8sIHdpZHRoX3N2ZyA9IDUsIGhlaWdodF9zdmcgPSAzKQoKYGBgCgojIyMgU3RlcCA5OiBEbyBzb21lIGJhc2ljIGFuYWx5c2lzCgpgYGB7cn0KY29vbGluZ2NlbnRlcnNjbGVhbiAlPiUgCiAgZmlsdGVyKHRyYW5zcG9ydGF0aW9uID09ICJZZXMiKQojTm8gY2VudGVycyBwcm92aWRlIHRyYW5zcG9ydGF0aW9uCgpjb29saW5nY2VudGVyc2NsZWFuICU+JSAKICBmaWx0ZXIoYWRhX2FjY2Vzc2libGUgPT0gIk5vIikKI0FsbCBjZW50ZXJzIGFyZSBBREEgYWNjZXNzaWJsZQoKY29vbGluZ2NlbnRlcnNjbGVhbiAlPiUgCiAgZ3JvdXBfYnkoY291bnR5KSAlPiUgCiAgY291bnQoY291bnR5KSAlPiUgCiAgYXJyYW5nZShkZXNjKG4pKQojSmFja3NvbiBDb3VudHkgaGFzIHRoZSBtb3N0IGNvb2xpbmcgY2VudGVycyBmb2xsb3dlZCBieSBTdC4gTG91aXMgY291bnR5IGFuZCB0aGVuIE1hZGlzb24KCmNvb2xpbmdjZW50ZXJzY2xlYW4gJT4lIAogIGZpbHRlcihjb3VudHkgPT0gIkJvb25lIikKI0Jvb25lIENvdW50eSBoYXMgNiBjb29saW5nIGNlbnRlcnMKCmNvb2xpbmdjZW50ZXJzY2xlYW4gJT4lIAogIGZpbHRlcihncmVwbCgic3VuIiwgaG91cnNfb2Zfb3BlcmF0aW9uLCBpZ25vcmUuY2FzZT1UKSkKIzU4IGNlbnRlcnMgYXJlIG9wZW4gb24gU3VuZGF5cwoKaGVhdGhvc3BpdGFsaXphdGlvbnMgJT4lIAogIGFycmFuZ2UoZGVzYyh2YWx1ZSkpCiNDYWxpZm9ybmlhIGhhZCB0aGUgaGlnaGVzdCBoZWF0LXJlbGF0ZWQgaG9zcGl0YWxpemF0aW9uIHJhdGUgaW4gMjAyMDsgTWlzc291cmkgaGFkIHRoZSBzaXh0aCBoaWdoZXN0IHJhdGUgaW4gMjAxMSBhdCA3LjYuCgpoZWF0aG9zcGl0YWxpemF0aW9ucyAlPiUgCiAgZmlsdGVyKHN0YXRlPT0iTWlzc291cmkiKSAlPiUgCiAgYXJyYW5nZShkZXNjKHZhbHVlKSkKI01pc3NvdXJpIGhhZCBpdHMgaGlnaGVzdCBudW1iZXIgb2YgaGVhdC1yZWxhdGVkIGhvc3BpdGFsaXphdGlvbnMgaW4gMjAxMQoKaGVhdGhvc3BpdGFsaXphdGlvbnMgJT4lIAogIHN1bW1hcmlzZShhdmVyYWdlID0gbWVhbih2YWx1ZSkpCiNUaGUgYXZlcmFnZSBwZXJjZW50YWdlIG9mIGhlYXQtcmVsYXRlZCBpbGxuZXNzIGhvc3BpdGFsaXphdGlvbnMgZnJvbSAyMDAwIHRvIDIwMjEgdXNpbmcgYXZhaWxibGUgZGF0YSB3YXMgMi4wMTAxMzMlLgoKaGVhdGhvc3BpdGFsaXphdGlvbnMgJT4lIAogIGdyb3VwX2J5KHN0YXRlKSAlPiUgCiAgc3VtbWFyaXNlKGF2ZXJhZ2UgPSBtZWFuKHZhbHVlKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhhdmVyYWdlKSkKI01pc3NvdXJpIGhhcyB0aGUgc2Vjb25kIGhpZ2hlc3QgcmF0ZSBvZiB0aGUgZGF0YSByZXBvcnRlZC4gCgoKYGBgCgojIyMgU3RvcnkgUGFja2FnZQoKKipJbXBvcnRhbnQgc3RhdGlzdGljcyBhbmQgZGF0YSBhbmFseXNpcyB0byBpbmNsdWRlIGluIHRoZSBzdG9yeToqKgoKSW4gdGhlIGxhc3QgdHdvIGRlY2FkZXMsIE1pc3NvdXJpIHJhbmtzIGluIHRoZSB0b3AgdGVuIG91dCBvZiByZXBvcnRpbmcgc3RhdGVzIGZvciB0aGUgaGlnaGVzdCByYXRlIG9mIGhlYXQtcmVsYXRlZCBpbGxuZXNzZXMgcGVyIDEwMCwwMDAgcGVvcGxlLiBJbiAyMDExLCB0aGUgcmF0ZSBpbiBNaXNzb3VyaSByZWFjaGVkIDcuNiUsIHJhbmtpbmcgaXQgbnVtYmVyIDYgYmVoaW5kIEFyaXpvbmEuCgpNaXNzb3VyaSBjdXJyZW50bHkgcmVwb3J0cyA1MzggY29vbGluZyBjZW50ZXJzLiA1OCBvZiB0aG9zZSBjb29saW5nIGNlbnRlcnMgYXJlIG9wZW4gb24gU3VuZGF5cy4KCioqR3JhcGhzIHRvIGluY2x1ZGUgaW4gdGhlIHN0b3J5OioqCgpgYGB7cn0KZG90bWFwCmBgYAoKYGBge3J9CmludGVyYWN0aXZlZG90bWFwCmBgYAoKYGBge3J9CmJhcl9ncmFwaApgYGAKCmBgYHtyfQpjaGxvcm9fbWFwCmBgYAoKIyMjIE1ldGhvZG9sb2d5OgoKVGhyZWUgZGF0YSBzZXRzIHdlcmUgdXNlZCBhbmQgYW5hbHl6ZWQgaW4gdGhpcyBzdG9yeSBwYWNrYWdlLgoKVGhlIGZpcnN0IGRhdGEgc2V0IGRvY3VtZW50cyB0aGUgbG9jYXRpb25zIG9mIGNvb2xpbmcgY2VudGVycyBpbiB0aGUgc3RhdGUgb2YgTWlzc291cmkuIFRoaXMgZGF0YSBpcyBmcm9tIDIwMjIgYW5kIHdhcyBjb2xsZWN0ZWQgZnJvbSBkYXRhLm1vLmdvdi4gSXQgaXMgcmVwb3J0ZWQgYnkgdGhlIE1pc3NvdXJpIERlcGFydG1lbnQgb2YgSGVhbHRoICYgU2VuaW9yIFNlcnZpY2VzLiBUaGUgZGF0YSBvbmx5IGluY2x1ZGVzIGNvb2xpbmcgY2VudGVycyB0aGF0IGFyZSByZXBvcnRlZCB0byB0aGUgTWlzc291cmkgRGVwYXJ0bWVudCBvZiBIZWFsdGggJiBTZW5pb3IgU2VydmljZXMsIGFuZCB0aGVyZWZvcmUgbWF5IGV4Y2x1ZGUgc29tZSBjb29saW5nIGNlbnRlcnMuCgpUaGUgc2Vjb25kIGRhdGEgc2V0IGRvY3VtZW50cyB0aGUgcGVyY2VudCBvZiBhZ2UtYWRqdXN0ZWQgaGVhdC1yZWxhdGVkIGlsbG5lc3MgaG9zcGl0YWxpemF0aW9ucyBpbiB0aGUgVW5pdGVkIFN0YXRlcyBwZXIgMTAwLDAwMCBwZW9wbGUuIEl0IHdhcyBhY2Nlc3NlZCBmcm9tIHRoZSBDZW50ZXJzIGZvciBEaXNlYXNlIENvbnRyb2wuIEl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgYWxsIHN0YXRlcyByZXBvcnQgZGF0YSBldmVyeSB5ZWFyLiBJbiBteSBhbmFseXNpcywgSSBpbmNsdWRlZCBhbGwgc3RhdGVzJyBkYXRhLiBJbiBjcmVhdGluZyB0aGUgYmFyIGNoYXJ0LCBob3dldmVyLCBJIGluY2x1ZGVkIGZpbHRlcmVkIGZvciBkYXRhIGZyb20gb25seSBNaXNzb3VyaSwgZm9yIGFsbCB5ZWFycyBhdmFpbGFibGUgZnJvbSAyMDAwIHRvIDIwMjEuCgpUaGUgdGhpcmQgZGF0YSBzZXQgZG9jdW1lbnRzIHRoZSBudW1iZXIgb2YgdW5zaGVsdGVyZWQgaW5kaXZpZHVhbHMgZXhwZXJpZW5jaW5nIGhvbWVsZXNzbmVzcyBpbiAyMDE5LCB3aGljaCBpcyB0aGUgbW9zdCByZWNlbnQgZGF0YSBhdmFpbGFibGUgZm9yIGRvd25sb2FkLiBJdCBjb21lcyBmcm9tIHRoZSBNaXNzb3VyaSBCYWxhbmNlIG9mIFN0YXRlIENvbnRpbnVhIG9mIENhcmUsIGFzIHJlcXVpcmVkIGJ5IHRoZSBNaXNzb3VyaSBEZXBhcnRtZW50IG9mIEhlYWx0aCAmIFNlbmlvciBTZXJ2aWNlcy4gU29tZSBjb3VudGllcyBhcmUgbm90IHJlcG9ydGVkIGluIHRoZSBkYXRhLiBJbiB0aGUgY2hhcnQsIHRoZXNlIGNvdW50aWVzIGFyZSBsaXN0ZWQgd2l0aCBkYXRhIGFzICJOL0EiLgoKKkFuaW1hdGlvbiBjb2RlOioKClRoaXMgY29kZSBtYXkgdGFrZSBhIHdoaWxlIHRvIGxvYWQsIGFuZCByZXF1aXJlcyByZW5kZXJpbmcgcGFja2FnZXMgdG8gc2hvdyB0aGUgYW5pbWF0aW9uLgoKYGBge3J9CmFuaW1hdGVkZ3JhcGggPC0gaGVhdGhvc3BpdGFsaXphdGlvbnMgJT4lIAogIGZpbHRlcihzdGF0ZT09Ik1pc3NvdXJpIiB8IHN0YXRlPT0iQXJpem9uYSIpICU+JSAKICBnZ3Bsb3QoYWVzKHg9c3RhdGUsIHk9dmFsdWUsIGZpbGw9c3RhdGUpKSArIAogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplID0gNyksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9NyksIHRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTcpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NykpICsKbGFicyh0aXRsZSA9ICJQZXJjZW50YWdlIG9mIGhlYXQtcmVsYXRlZCBpbGxuZXNzIGhvc3BpdGFsaXphdGlvbnMgaW4gTWlzc291cmkgYW5kIEFyaXpvbmEgcGVyIDEwMGsgcGVvcGxlIDIwMDAtMjAyMCIsIHN1YnRpdGxlID0gIkRhdGEgZnJvbSBDREMiKSArCnlsYWIoIlBlcmNlbnRhZ2Ugb2YgaGVhdCBob3NwaXRhbGl6YXRpb25zIikgKwp4bGFiKCJZZWFyIikKCiBhbmltYXRlZGdyYXBoICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArCiAgdHJhbnNpdGlvbl9zdGF0ZXMoCiAgICB5ZWFyLAogICAgdHJhbnNpdGlvbl9sZW5ndGggPSAyMCwKICAgIHN0YXRlX2xlbmd0aCA9IDEpICsKICBlYXNlX2Flcygnc2luZS1pbi1vdXQnKSArCiAgICAgdHJhbnNpdGlvbl90aW1lKHllYXIpICsKbGFicyh0aXRsZSA9ICJZZWFyOiB7ZnJhbWVfdGltZX0iKQoKCmBgYAo=